package com.example.demo.config;

import com.example.demo.config.shiro.cache.CustomCacheManager;
import com.example.demo.config.shiro.filter.JwtFilter;
import com.example.demo.config.shiro.realme.CustomRealm;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro配置类
 *
 * @author 幻
 * @date 2021-05-18 16:02
 */
@Configuration
public class ShiroConfig {
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager(CustomRealm realm, RedisTemplate<String, Object> template) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //使用JdkSerializationRedisSerializer
        template.setHashValueSerializer(new JdkSerializationRedisSerializer());
        //开启缓存管理
        realm.setCacheManager(new CustomCacheManager(template));
        //开启全局缓存
        realm.setCachingEnabled(true);
        //开启认证缓存
        realm.setAuthenticationCachingEnabled(true);
        realm.setAuthenticationCacheName("authenticationCache");
        //开启授权缓存
        realm.setAuthorizationCachingEnabled(true);
        realm.setAuthorizationCacheName("authorizationCache");
        // 设置自定义 realm.
        securityManager.setRealm(realm);

        //关闭session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);

        //设置自定义Cache缓存
        securityManager.setCacheManager(new CustomCacheManager(template));
        return securityManager;
    }

    /**
     * 先走 filter ，然后 filter 如果检测到请求头存在 token，则用 token 去 login，走 Realm 去验证
     */
    @Bean
    public ShiroFilterFactoryBean factory(@Qualifier("securityManager") DefaultWebSecurityManager securityManager
            , ShiroFilterChainDefinition shiroFilterChainDefinition, @Qualifier("jwtFilterRegBean") FilterRegistrationBean jwtFilterRegBean) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);

        //设置我们自定义的JWT过滤器
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        filterMap.put("jwt", jwtFilterRegBean.getFilter());
        factoryBean.setFilters(filterMap);
        //设置过滤器链
        factoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());
        return factoryBean;
    }

    /**
     * 在此处配置过滤器链
     */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        //这些请求不通过jwtFilter
        chainDefinition.addPathDefinition("/swagger-ui.html", "anon");
        chainDefinition.addPathDefinition("/swagger-resources/**", "anon");
        chainDefinition.addPathDefinition("/v2/api-docs", "anon");
        chainDefinition.addPathDefinition("/webjars/springfox-swagger-ui/**", "anon");

        chainDefinition.addPathDefinition("/druid/stat","anon");
        chainDefinition.addPathDefinition("/druid/**","anon");
        chainDefinition.addPathDefinition("/user/binding", "anon");
//        chainDefinition.addPathDefinition("/user/register", "anon");
        chainDefinition.addPathDefinition("/user/appLogin", "anon");
        chainDefinition.addPathDefinition("/user/unauthorized", "anon");
        // 所有请求通过我们自己的JWT Filter
        chainDefinition.addPathDefinition("/**", "jwt");
        return chainDefinition;
    }

    /**
     * 配置JwtFilter过滤器,并设置为未注册状态
     */
    @Bean
    public FilterRegistrationBean jwtFilterRegBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        //添加JwtFilter  并设置为未注册状态
        filterRegistrationBean.setFilter(new JwtFilter());
        filterRegistrationBean.setEnabled(false);
        return filterRegistrationBean;
    }

    /**
     * 添加注解支持，如果不加的话很有可能注解失效
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {

        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {

        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
}
